﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using NUnit.Framework;
using SharePoint.Orm.TestHelpers;
using SharePoint.Orm.Wrappers;
using SPGenerated;
using SPGenerated.ContentTypes;
using SPGenerated.Lists;

namespace SharePoint.Orm {
	[TestFixture]
	public class SPDataContextTest : TestBase {
		private int _item1Id;
		private int _item2Id;
		private MySPDataContext _ctx;

		[TestFixtureSetUp]
		public override void TestInitialize() {
			base.TestInitialize();
			SiteHelpers.EnsureSite();
			SiteHelpers.RemoveData();

			_ctx = new MySPDataContext(SiteHelpers.Url);

			SPList list = SiteHelpers.EnsureList1(_ctx.Site);

			SPListItem item1 = list.Items.Add();
			item1["Title"] = "Item1";
			item1[SiteHelpers.Field1Name] = "Item1";
			item1.Update();
			_item1Id = item1.ID;

			SPListItem item2 = list.Items.Add();
			item2["Title"] = "Item2";
			item2[SiteHelpers.Field1Name] = "Item2";
			item2.Update();
			_item2Id = item2.ID;
		}

		[TestFixtureTearDown]
		public override void TestCleanup() {
			base.TestCleanup();
			_ctx.Dispose();
		}

		[Test]
		public void TestExecuteCaml() {
			const string caml = @"<Where>
<Eq>
	<FieldRef Name='" + SiteHelpers.Field1Name + @"' />
	<Value Type='Text'>Item2</Value>
</Eq></Where>";
			List<ContentType1> items = _ctx.ExecuteCaml<List1, ContentType1>(caml).ToList();
			Assert.AreEqual(1, items.Count);
			Assert.AreEqual("Item2", items[0].Field1);
		}

		[Test]
		public void TestWhereTypeId() {
			ContentType1[] items = _ctx.List1.OfType<ContentType1>().ToArray();
			foreach (ContentType1 item in items) {
				Console.WriteLine(item.Id + " - " + item.Field1);
			}
			Assert.AreEqual(2, items.Count());
			Assert.AreEqual(1, items.Count(c => c.Id == _item1Id));
			Assert.AreEqual(1, items.Count(c => c.Id == _item2Id));
		}

		[Test]
		public void TestWhereTypeIdAndWhere() {
			ContentType1[] items = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).ToArray();
			foreach (ContentType1 item in items) {
				Console.WriteLine(item.Id + " - " + item.Field1);
			}
			Assert.AreEqual(1, items.Count());
			Assert.AreEqual("Item1", items[0].Field1);
		}

		[Test]
		public void TestSaveNewObject() {
			ContentType1 newObj = new ContentType1 {
				Title = "new object",
				Field1 = "field1: new object",
				Field4SiteStaticName = "field4"
			};
			int id = _ctx.Save<List1>(newObj);
			ContentType1 fetchedObj = _ctx.List1.OfType<ContentType1>().SingleOrDefault(e => e.Id == id);
			Assert.IsNotNull(fetchedObj);
			Assert.AreEqual("new object", fetchedObj.Title);
			Assert.AreEqual("field1: new object", fetchedObj.Field1);
			Assert.AreEqual("field4", fetchedObj.Field4SiteStaticName);
		}

		[Test]
		public void TestSaveOldObject() {
			ContentType1 item = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).FirstOrDefault();
			item.Title = "new title";
			_ctx.Update(item);

			ContentType1 fetchedItem = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).FirstOrDefault();
			Assert.AreEqual("new title", fetchedItem.Title);
		}

		[Test]
		public void TestDelete() {
			ContentType1 item = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).FirstOrDefault();
			_ctx.Delete(item);
			ContentType1 found = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).FirstOrDefault();
			Assert.IsNull(found);
		}

		[Test]
		public void TestDeleteAll() {
			_ctx.DeleteAll(_ctx.List1);
			SPList list = _ctx.GetSPList<List1>();
			Assert.AreEqual(0, list.Items.Count);
		}

		[Test]
		public void TestGetSPListItem_WithSpListItem() {
			SPListItem item1 = _ctx.Site.Lists[SiteHelpers.List1Name].Items.GetItemById(_item1Id);
			SPListItem found = _ctx.GetSPListItem(item1);
			Assert.AreEqual(_item1Id, found.ID);
		}

		[Test]
		public void TestGetSPListItem() {
			ContentType1 item = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).FirstOrDefault();
			SPListItem listItem = _ctx.GetSPListItem(item);
			Assert.IsNotNull(listItem);
			Assert.AreEqual(_item1Id, listItem.ID);
		}

		[Test]
		public void TestAttach_ContentType() {
			SPListItem listItem = _ctx.Site.Lists[SiteHelpers.List1Name].Items.Cast<SPListItem>().FirstOrDefault(li => li.ID == _item1Id);
			ContentType1 contentType1 = _ctx.Attach<ContentType1>(listItem);
			Assert.AreEqual(_item1Id, contentType1.Id);
		}

		[Test]
		public void TestAttach_List() {
			SPListItem listItem = _ctx.Site.Lists[SiteHelpers.List1Name].Items.Cast<SPListItem>().FirstOrDefault(li => li.ID == _item1Id);
			List1 list1Item = _ctx.Attach<List1>(listItem);
			Assert.AreEqual(_item1Id, list1Item.Id);
		}

		[Test]
		public void TestTypes() {
			SPUser user = _ctx.Site.Users[0];

			SPListItem listItem = _ctx.Site.Lists[SiteHelpers.List4Name].Items.Add();
			listItem[SiteHelpers.List4FieldText] = "text";
			listItem[SiteHelpers.List4FieldDateTime] = new DateTime(2009, 7, 16, 1, 2, 3);
			listItem[SiteHelpers.List4FieldNote] = "note";
			listItem[SiteHelpers.List4FieldInteger] = 42;
			listItem[SiteHelpers.List4FieldGuid] = new Guid("26CBAD64-68F0-4422-8B73-51FAF8E399A9");
			listItem[SiteHelpers.List4FieldBoolean] = true;
			listItem[SiteHelpers.List4FieldChoice] = "a";
			//listItem[SiteHelpers.List4FieldFile] = "";
			//listItem[SiteHelpers.List4FieldComputed] = "";
			listItem[SiteHelpers.List4FieldUser] = new SPFieldUserValue(_ctx.Site, user.ID, user.Name);
			//listItem[SiteHelpers.List4FieldInvalid] = "";
			//listItem[SiteHelpers.List4FieldWorkflowStatus] = "";
			listItem[SiteHelpers.List4FieldURL] = new SPFieldUrlValue { Description = "url", Url = "http://myurl" };
			//listItem[SiteHelpers.List4FieldAllDayEvent] = "";
			//listItem[SiteHelpers.List4FieldRecurrence] = "";
			//listItem[SiteHelpers.List4FieldCrossProjectLink] = "";
			listItem[SiteHelpers.List4FieldNumber] = 23.5;
			listItem[SiteHelpers.List4FieldWorkflowEventType] = "";
			listItem.Update();

			List4Item item = _ctx.List4.OfType<List4Item>().FirstOrDefault();
			Assert.AreEqual("text", item.List4FieldText);
			Assert.AreEqual(new DateTime(2009, 7, 16, 1, 2, 3), item.List4FieldDateTime);
			Assert.AreEqual("note", item.List4FieldNote);
			Assert.AreEqual(42, item.List4FieldInteger);
			Assert.AreEqual(new Guid("26CBAD64-68F0-4422-8B73-51FAF8E399A9"), item.List4FieldGuid);
			Assert.AreEqual(true, item.List4FieldBoolean);
			Assert.AreEqual("a", item.List4FieldChoice);
			//Assert.AreEqual(,item.List4FieldFile); 
			//Assert.AreEqual(,item.List4FieldComputed); 
			Assert.AreEqual(user.LoginName, item.List4FieldUser.User.LoginName);
			//Assert.AreEqual(,item.List4FieldInvalid); 
			//Assert.AreEqual(,item.List4FieldWorkflowStatus); 
			Assert.AreEqual("url", item.List4FieldURL.Description);
			Assert.AreEqual("http://myurl", item.List4FieldURL.Url);
			//Assert.AreEqual(,item.List4FieldAllDayEvent); 
			//Assert.AreEqual(,item.List4FieldRecurrence); 
			//Assert.AreEqual(,item.List4FieldCrossProjectLink); 
			Assert.AreEqual(23.5M, item.List4FieldNumber);
			Assert.AreEqual(null, item.List4FieldWorkflowEventType);
		}

		[Test]
		public void TestLookupFieldGetValue() {
			SPListItem listItem = _ctx.Site.Lists[SiteHelpers.List4Name].Items.Add();
			listItem[SiteHelpers.List4FieldLookup] = new SPFieldLookupValue(_item1Id, "Item1");
			listItem.Update();

			List4Item item = _ctx.List4.OfType<List4Item>().FirstOrDefault();
			Assert.AreEqual(_item1Id, item.List4FieldLookup.Id);
			Assert.AreEqual(_item1Id, item.List4FieldLookupId.LookupId);
		}

		[Test]
		public void TestLookupFieldSetValue_NewObject() {
			ContentType1 list1Item = _ctx.List1.OfType<ContentType1>().FirstOrDefault(i => i.Id == _item1Id);
			List4Item newObj = new List4Item {
				List4FieldLookup = _ctx.Cast<List1>(list1Item)
			};
			int newObjId = _ctx.Save<List4>(newObj);

			SPListItem listItem = _ctx.Site.Lists[SiteHelpers.List4Name].Items.Cast<SPListItem>().FirstOrDefault(i => i.ID == newObjId);
			SPFieldLookupValue lookupValue = new SPFieldLookupValue((string)listItem[SiteHelpers.List4FieldLookup]);
			Assert.AreEqual(_item1Id, lookupValue.LookupId);
		}

		[Test]
		public void TestGetSPList() {
			SPList list = _ctx.GetSPList<List1>();
			Assert.IsNotNull(list);
			Assert.AreEqual("List1", list.Title);
		}

		[Test]
		public void TestAddFile() {
			int itemId;
			using (MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes("hello world"))) {
				List5 item = _ctx.AddFile<List5>("test.txt", stream);
				itemId = item.Id;
				using (Stream dataStream = item.OpenBinaryStream())
				using (StreamReader dataStreamReader = new StreamReader(dataStream)) {
					string dataStreamData = dataStreamReader.ReadToEnd();
					Assert.AreEqual("hello world", dataStreamData);
				}
			}
			SPListItem listItem = _ctx.Site.Lists[SiteHelpers.List5Name].Items.Cast<SPListItem>().FirstOrDefault(li => li.ID == itemId);
			Assert.IsNotNull(listItem);
			byte[] listItemData = listItem.File.OpenBinary();
			string listItemDataStr = Encoding.ASCII.GetString(listItemData);
			Assert.AreEqual("hello world", listItemDataStr);
		}

		[Test]
		public void TestRunInElevatedSite() {
			ContentType1 item = _ctx.List1.OfType<ContentType1>().Where(e => e.Id == _item1Id).FirstOrDefault();
			_ctx.RunInElevatedSite<MySPDataContext, ContentType1>(item, (elevCtx, elevObj) => {
				SPWeb elevSite = elevCtx.Site;
				SPListItem listItem = elevCtx.GetSPListItem(elevObj);
				Assert.IsNotNull(listItem);
				Assert.AreEqual("System Account", elevSite.CurrentUser.Name);
			});
		}

		[Test]
		public void TestGetField() {
			ISPOrmField field = _ctx.GetField<ContentType1>(c => c.Field1);
			Assert.AreEqual(ContentType1.FieldTitles.Field1, field.Title);
			Assert.AreEqual(ContentType1.FieldStaticName.Field1, field.StaticName);
		}

		[Test]
		public void TestSaveNewItemBasedOnContact() {
			ContentType2 ct2 = new ContentType2 {
				Title = "smith",
				FirstName = "bob"
			};
			_ctx.Save<List6>(ct2);
		}
	}
}
